#ifndef _SHELL_H
#define _SHELL_H

#include "string.h"
#include "shell_cfg.h"
#include "shell_ext.h"
#include "ctype.h"



#if defined(__CC_ARM) || (defined(__ARMCC_VERSION) && __ARMCC_VERSION >= 6000000)
#define SECTION(x)                  __attribute__((section(x)))
#elif defined(__ICCARM__)
#define SECTION(x)                  @ x
#elif defined(__GNUC__)
#define SECTION(x)                  __attribute__((section(x)))
#else
#define SECTION(x)
#endif


#if SHELL_USING_CMD_EXPORT == 1
#if SHELL_LONG_HELP == 1

#define     SHELL_EXPORT_CMD(cmd, func, desc)                               \
            const char shellCmd##cmd[] = #cmd;                              \
            const char shellDesc##cmd[] = #desc;                            \
            const SHELL_CommandTypeDef                                      \
            shellCommand##cmd SECTION("shellCommand") =                     \
            {                                                               \
                shellCmd##cmd,                                              \
                (int (*)())func,                                            \
                shellDesc##cmd,                                             \
                (void *)0                                                   \
            }

#define     SHELL_EXPORT_CMD_EX(cmd, func, desc, help)                      \
            const char shellCmd##cmd[] = #cmd;                              \
            const char shellDesc##cmd[] = #desc;                            \
            const char shellHelp##cmd[] = #help;                            \
            const SHELL_CommandTypeDef                                      \
            shellCommand##cmd SECTION("shellCommand") =                     \
            {                                                               \
                shellCmd##cmd,                                              \
                (int (*)())func,                                            \
                shellDesc##cmd,                                             \
                shellHelp##cmd                                              \
            }

#else 
#define     SHELL_EXPORT_CMD(cmd, func, desc)                               \
            const char shellCmd##cmd[] = #cmd;                              \
            const char shellDesc##cmd[] = #desc;                            \
            const SHELL_CommandTypeDef                                      \
            shellCommand##cmd SECTION("shellCommand") =                     \
            {                                                               \
				#cmd,                                                       \
                (int (*)())func,                                            \
				#desc                                                       \
            }

#define     SHELL_EXPORT_CMD_EX(cmd, func, desc, help)                      \
            const char shellCmd##cmd[] = #cmd;                              \
            const char shellDesc##cmd[] = #desc;                            \
            const SHELL_CommandTypeDef                                      \
            shellCommand##cmd SECTION("shellCommand") =                     \
            {                                                               \
				#cmd,                                                       \
                (int (*)())func,                                            \
				#desc,                                                      \
            }

#endif
#else 
#define     SHELL_EXPORT_CMD(cmd, func, desc)
#define     SHELL_EXPORT_CMD_EX(cmd, func, desc, help)

#endif // SHELL_USING_CMD_EXPORT == 1

#if SHELL_USING_CMD_EXPORT == 0
//#if SHELL_LONG_HELP		==	1

#define     SHELL_CMD_ITEM(cmd, func, desc)                                 \
            {                                                               \
				#cmd,                                                       \
                (int (*)())func,                                            \
				#desc,                                                      \
                (void *)0                                                   \
            }
#define     SHELL_CMD_ITEM_EX(cmd, func, desc, help)                        \
            {                                                               \
				#cmd,                                                       \
                (int (*)())func,                                            \
				#desc,                                                      \
				#help                                                       \
            } 

#else
#define     SHELL_CMD_ITEM(cmd, func, desc)                                 \
            {                                                               \
				#cmd,                                                       \
                (int (*)())func,                                            \
				#desc                                                       \
            }
#define     SHELL_CMD_ITEM_EX(cmd, func, desc, help)                        \
            {                                                               \
				#cmd,                                                       \
                (int (*)())func,                                            \
				#desc,                                                      \
            }  
#endif
//#endif


/*
 *char 0 read success
 *char -1 read failed
 **/

typedef signed char(*shellReadtype)(char *);


typedef void(*shellWritetype)(const char);


typedef int(*shellFunction)();


typedef enum
{
	SHELL_IN_NORMAL = 0,
	SHELL_ANSI_ESC,
	SHELL_ANSI_CSI,
}SHELL_InputMode;

typedef struct
{
	const char *name; 		//shell name
	shellFunction function; 	//shell function
	const char *desc; 		//description of shell function
	const char *help; 		//help information

}SHELL_CommandTypeDef;


typedef struct
{
	char *command; 							//shell command tip
	char buffer[SHELL_COMMAND_MAX_LENGTH]; 	//shell command buffer
	unsigned short length; 					//shell command length
	unsigned short cursor; 					//shell cursor 
	char *param[SHELL_HISTORY_MAX_NUMBER]; 	//shell parameter
	char history[SHELL_HISTORY_MAX_NUMBER][SHELL_COMMAND_MAX_LENGTH]; //shell cmd history
	unsigned short historyCount; 			//history number
	short historyFlag; 						//history location
	short historyOffset; 					//history location offset
	SHELL_CommandTypeDef *commandBase; 		//cmd base address
	unsigned short commandNumber; 			//cmd number
	SHELL_InputMode status; 					//input status
	unsigned char isActive; 					//is an active cmd shell
	shellReadtype read; 							//shell read 
	shellWritetype write;  						//shell write
}SHELL_TypeDef;


void shellInit(SHELL_TypeDef *shell);
void shellSetCommandList(SHELL_TypeDef *shell, SHELL_CommandTypeDef *base, unsigned short size);
SHELL_TypeDef *shellGetCurrent(void);
unsigned short shellDisplay(SHELL_TypeDef *shell, const char *string);
void shellHandler(SHELL_TypeDef *shell, char data);

void shellHelp(int argc, char *argv[]);
void shellClear(void);
void STM32_ID(void);


void shellTask(SHELL_TypeDef *param, char data);

void Shell_Out_Char(const char outdata);
signed char Shell_In_Char(char *indata);

#endif // !_SHELL_H
